﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

using Complete.Data.Linq;
using Complete.Data.Linq.Expressions;

namespace Complete.Data
{
	public class ColumnMapping
	{
		public ColumnMapping(string columnName, PropertyInfo memberInfo)
		{
			this.MemberInfo = memberInfo;
			this.ColumnName = columnName;
		}

		public PropertyInfo MemberInfo { get; private set; }
		public string ColumnName { get; private set; }
	}

	public class AssociationMapping
	{
		public AssociationMapping(ITableDefinition definition, LambdaExpression joinExpression, JoinType joinType)
		{
			this.TableDefinition = definition;
			this.JoinExpression = joinExpression;
			this.JoinType = joinType;
		}

		public static AssociationMapping CreateAssociation<T, U>(ITableDefinition definition, Expression<Func<T, U, bool>> joinExpression, JoinType joinType)
		{
			return new AssociationMapping(definition, (LambdaExpression)joinExpression, joinType);
		}

		public ITableDefinition TableDefinition { get; private set; }
		public LambdaExpression JoinExpression { get; private set; }
		public JoinType JoinType { get; private set; }
	}

	public interface INameMapper
	{
		bool CanHandleType(Type t);
		string GetTableName(Type t);
		IEnumerable<ColumnMapping> GetColumns(Type t);
		IEnumerable<ColumnMapping> GetPrimaryKeyColumns(Type t);
		AssociationMapping GetRelationship(MemberInfo member);
	}

	public sealed class DefaultNameMapper : INameMapper
	{
		public static IEnumerable<ColumnMapping> GetColumnsForType(Type t)
		{
			foreach (var p in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
			{
				yield return new ColumnMapping(p.Name, p);
			}
		}

		public bool CanHandleType(Type t)
		{
			return true;
		}

		public string GetTableName(Type t)
		{
			return t.Name;
		}

		public IEnumerable<ColumnMapping> GetColumns(Type t)
		{
			return DefaultNameMapper.GetColumnsForType(t);
		}

		public IEnumerable<ColumnMapping> GetPrimaryKeyColumns(Type t)
		{
			return DefaultNameMapper.GetColumnsForType(t);
		}

		public AssociationMapping GetRelationship(MemberInfo member)
		{
			throw new NotSupportedException("This name mapper does not support table relationships.");
		}
	}
}
